import {
  shallowRef,
  onMounted,
  nextTick,
  reactive,
  onBeforeUnmount,
  ref,
  computed,
  watch
} from 'vue';
import type { Ref } from 'vue';
import BScroll from 'better-scroll';
import { TReducer } from '@/types/hooks';
import type { IFieldItemData, IHomeData, IInfoSearchState, TListData } from '@/types/data';
import { useCityStore } from '@/store';
import { fields } from '@/assets/data';
import { trimSpace, throttle } from '@/utils/tools';
import { searchHttpService, indexHttpService, listHttpService, detailHttpService } from '@/services';
import { detailLogger, homeLogger, listLogger, searchLogger } from '@/utils/Logger';
import { useRoute } from 'vue-router';

/**
 * @function `useBScroll`
 * @description 使用 BScroll 的 hook
 */
export function useBScroll() {
  const wrapperRef = shallowRef<HTMLDivElement | null>(null);
  const betterScroll = shallowRef<BScroll | null>(null);

  nextTick(() => {
    setTimeout(() => {
      if (!wrapperRef.value) return;

      betterScroll.value = new BScroll(wrapperRef.value, {
        mouseWheel: true,
        scrollX: true,
        scrollY: true,
        click: true,
        bounce: true,
        tap: 'tap',
      });
    }, 666);
  });

  onBeforeUnmount(() => {
    if (!betterScroll.value) return;
    betterScroll.value.destroy();
    betterScroll.value = null;
  });

  return {
    wrapperRef,
    betterScroll,
  };
}

/**
 * @function `useState`
 * @description 使用 Vue state 的 hook
 */
export function useState<T>(
  initialValue: T | (() => T),
): [Ref<T>, (setter: T | ((prevValue: T) => T)) => void] {
  const _initialValue: T = _getInitialValue(initialValue);
  const stateRef: Ref<T> = <Ref<T>> ref(_initialValue);

  const setStateRef = (setter: T | ((prevValue: T) => T)) => {
    if (typeof setter === 'function') {
      const prevValue: T = stateRef.value;
      stateRef.value = (setter as ((prevValue: T) => T))(prevValue);
    } else {
      stateRef.value = setter;
    }
  }

  return [stateRef, setStateRef];

  function _getInitialValue(target: T | (() => T)): T {
    if (typeof target === 'function') {
      return (target as (() => T))() as T;
    }
    return target;
  }
}

/**
 * @function `useReducer`
 * @description 使用 Vue reducer 的 hook
 */
export function useReducer<State extends Record<string, any>>(
  reducer: TReducer,
  initialValue: State,
  initArgs?: (initialState: State) => State,
): [Ref<State>, (action: Parameters<TReducer>[1]) => Parameters<TReducer>[1]] {
  const initialState: State = initArgs ? initArgs(initialValue) : initialValue;
  const [state, setState] = useState(initialState);

  const dispatch = (action: Parameters<TReducer>[1]) => {
    const newState = reducer(state.value, action);
    setState(newState);
    return action;
  }

  return [state, dispatch];
}

/**
 * @function useFieldInfo
 * @description 根据 fieldInfo 筛选 store.field 对应的值
 */
export function useFieldInfo() {
  const cityStore = useCityStore();

  const fieldInfo = computed(() => {
    const field = cityStore.field;
    
    const fieldItem = fields.find(item => item.field === field);

    return fieldItem ?? fields[0];
  });

  return fieldInfo;
}

/**
 * @function useCityId
 * @description 获取 cityId
 */
export function useCityId() {
  const cityStore = useCityStore();

  const cityId = computed(() => cityStore.cityId);

  return cityId;
}

/**
 * @function useField
 * @description 获取 field
 */
export function useField() {
  const cityStore = useCityStore();

  const field = computed(() => cityStore.field);

  return field;
}

/**
 * @function useInfoSearch
 * @description 根据信息进行搜索的逻辑
 */
export function useInfoSearch(
  setLoadingShow: (loading: boolean) => void,
  setErrorShow: (errorShow: boolean) => void, 
) {
  const cityStore = useCityStore();

  const state = reactive<IInfoSearchState>({
    keyword: '',
    placeholder: '美食 / 景点 / 酒店 / 按摩 / KTV',
    searchData: {
      // cityDatas: [],
    },
  });

  const cityId = computed(() => cityStore.cityId);

  const onKeywordSearch = throttle(async (newValue: string) => {
    state.keyword = newValue;

    const keyword: string = trimSpace(state.keyword);

    if (!keyword.length) {
      state.searchData = {};
      return;
    }
    const requestParams = {
      cityId: cityId.value,
      keyword: state.keyword,
    };

    try {
      setLoadingShow(true);
      const { code, message, data } = await searchHttpService.searchAction(requestParams);
      if (code === 0) {
        searchLogger.success('搜索成功 !');
        state.searchData = data;
        setLoadingShow(false);
        setErrorShow(false);
      } else {
        throw new Error(message);
      }
    } catch (e) {
      state.searchData = {};
      setLoadingShow(false);
      setErrorShow(true);
      searchLogger.error(`搜索失败：${e instanceof Error ? e.message : String(e)}!`);
    }
  }, 1000);

  return {
    state,
    onKeywordSearch,
  };
}

/**
 * @function useHomeDatas
 * @description 首页数据获取
 */
export function useHomeDatas([, setErrorShow]: ReturnType<typeof useState<boolean>>) {
  const cityId = useCityId();

  const state = reactive<IHomeData>({
    foodDatas: [],
    hotelDatas: [],
    ktvDatas: [],
    massageDatas: [],
    viewDatas: [],
  });

  const homeTitleInfo = {
    foodTitle: '推荐美食',
    hotelTitle: '推荐酒店',
    ktvTitle: '推荐KTV',
    massageTitle: '推荐按摩',
    viewTitle: '推荐景点',
  };

  async function getHomeDatas() {
    try {
      const { data, code, message } = await indexHttpService.getListDatas(cityId.value);

      if (code === 0) {
        state.foodDatas = data.foodDatas;
        state.hotelDatas = data.hotelDatas;
        state.ktvDatas = data.ktvDatas;
        state.massageDatas = data.massageDatas;
        state.viewDatas = data.viewDatas;

        homeLogger.info('获取首页数据成功 !');

        setErrorShow(false);
      } else {
        homeLogger.error(message);
        setErrorShow(true);
      }
    } catch (e) {
      homeLogger.error(`获取首页数据失败：${e instanceof Error ? e.message : String(e)}!`)
      setErrorShow(true);
    }
  }

  watch(cityId, () => {
    getHomeDatas();
  });

  onMounted(() => {
    getHomeDatas();
  });

  return {
    homeTitleInfo,
    state
  };
}

/**
 * @function useListDatas
 * @description 获取列表页的数据
 */
export function useListDatas(
  setLoadingShow: (loading: boolean) => void,
  setErrorShow: (error: boolean) => void
) {
  const cityId = useCityId();
  const field = useField();

  const listDatas = ref<{ [key: string]: TListData }>({});

  async function getListData() {
    try {
      if (listDatas.value[field.value]?.length) return;

      setLoadingShow(true);

      const { code, message, data } = await listHttpService.getListDatas(cityId.value, field.value);
      if (code !== 0) {
        throw new Error(message);
      } else {
        listDatas.value[field.value] = data;
        setLoadingShow(false);
      }
    } catch (e) {
      setLoadingShow(false);
      setErrorShow(true);
      listLogger.error(
        `获取列表数据失败: ${e instanceof Error ? e.message : String(e)}`
      );
    }
  }

  onMounted(() => {
    getListData();
  });

  return listDatas;
}

/**
 * @function useDetailDatas
 * @description 获取详情页的数据
 */
export function useDetailDatas(
  setLoadingShow: (loading: boolean) => void,
  setErrorShow: (errorShow: boolean) => void,
) {
  const route = useRoute();

  const detailData = ref<Partial<IFieldItemData>>({});
  
  const queryField = computed(() => String(route.query.field));

  const queryId = computed(() => String(route.query.id));

  async function getDetailsData() {
    try {
      setLoadingShow(true);

      const { code, data, message } = await detailHttpService.getDetail(queryId.value);

      if (code === 0) {
        detailData.value = data;
        setLoadingShow(false);
        setErrorShow(false);
        detailLogger.success('获取详情数据成功 !');
      } else {
        throw new Error(message);
      }
    } catch (e) {
      setLoadingShow(false);
      setErrorShow(true);
      detailLogger.error(`获取详情数据失败：${e instanceof Error ? e.message : String(e)}!`);
    }
  }

  onMounted(() => {
    getDetailsData();
  });

  return {
    queryField,
    detailData,
  };
}
